<?php
/**
 * $Date: 2010-08-12 19:51:22 +0000 (Thu, 12 Aug 2010) $
 * $Author: manuelcanepa@gmail.com $
 * $Revision: 3 $
 * $URL: http://librerias-utiles.googlecode.com/svn/trunk/librerias-utiles/libs/Zend/Translate/Adapter/Db.php $
 */
require_once 'Zend/Locale.php';
require_once 'Zend/Translate/Adapter.php';
class Zend_Translate_Adapter_Db extends Zend_Translate_Adapter
{
    /**
     * Mensaje a traducir
     */
    const ZTAD_MENSAJE_ID = 'mensajeId';

    /**
     * Locale al cual va a ser traducido
     */
    const ZTAD_LOCALE = 'locale';

    /**
     * Mensaje traducido
     */
    const ZTAD_MENSAJE = 'mensaje';

    /**
     * Posibilidad de cargar secciones para obtener diferentes
     * traducciones de un mismo mensaje segun la seccion
     */
    const ZTAD_SECCION = 'seccion';

    /**
     * Relacion de las columnas
     *
     * @var array
     */
    protected $_tableColumns = array(
        self::ZTAD_MENSAJE_ID => 'mensajeId',
        self::ZTAD_LOCALE => 'locale',
        self::ZTAD_MENSAJE => 'mensaje',
        self::ZTAD_SECCION => ''
    );
    /**
     * Database adapter instance
     * @var Zend_Db_Adapter
     */
    protected $_db = null;

    /**
     * Generamos el adaptador
     *
     * @param  array               $data     Mensaje a traducir
     * @param  string|Zend_Locale  $locale   Opcional Locale/Idioma para setear.
     * @param  array               $options  Opcional Opciones adicionales
     */
    public function __construct($data, $locale = null, array $options = array())
    {
        if (!is_array($data))
        {
            $newData['dbTable'] = $data;
            $data = $newData;
            unset($newData);
        } else
        {
            if (!isset($data['dbTable']))
            {
                require_once 'Zend/Translate/Exception.php';
                throw new Zend_Translate_Exception('dbTable es un indice requerido si se usa $data como array');
            }
        }

        if (isset($data['tableColumns']))
        {
            $this->setTableColumns((array)$data['tableColumns']);
            unset($data['tableColumns']);
        }

        $this->_db = $data['dbTable'];

        parent::__construct($data['dbTable'], $locale, $options);
    }

    /**
     *
     * @param string $columna
     * @param string $valor
     * @return Zend_Translate_Adapter_Db
     */
    public function setTableColumn($columna, $valor)
    {
        if (array_key_exists($columna, $this->_tableColumns))
        {
            $this->_tableColumns[$columna] = $valor;
        }
        return $this;
    }

    public function setTableColumns(array $columns)
    {
        foreach ($columns as $columna => $valor)
        {
            $this->setTableColumn($columna, $valor);
        }
        return $this;
    }

    /**
     *
     * @param <type> $dbTable
     * @param <type> $locale
     * @param <type> $options
     */
    protected function _loadTranslationData($dbTable, $locale,
            array $options = array())
    {
        $options = array_merge($this->_options, $options);

        if (is_string($dbTable))
        {
            try
            {
                require_once 'Zend/Loader.php';
                Zend_Loader::loadClass($dbTable);
                $dbTable = new $dbTable;
            } catch (Exception $e)
            {
                $dbTable = false;
            }
        }

        if (!$dbTable instanceof Zend_Db_Table_Abstract)
        {
            require_once 'Zend/Translate/Exception.php';
            throw new Zend_Translate_Exception(
                    "La base de datos debe ser una instacia de 'Zend_Db_Table_Abstract'"
            );
        }

        /**
         * Resetea el array de traduccion
         */
        if ($options['clear'] || !isset($this->_translate[$locale]))
        {
            $this->_translate[$locale] = array();
        }

        $colMessageId = $this->_tableColumns[self::ZTAD_MENSAJE_ID];
        $colLocale = $this->_tableColumns[self::ZTAD_LOCALE];
        $colMessage = $this->_tableColumns[self::ZTAD_MENSAJE];
        $seccion = $this->_tableColumns[self::ZTAD_SECCION];

        /**
         * Lista todos los registros en el array
         */
        $translates = $dbTable->fetchAll(
                        array(
                            "$colLocale = ?" => $locale
                        ),
                        array(
                            $colMessageId
                        )
        );

        foreach ($translates as $translate)
        {
            $messageId = $translate->$colMessageId;
            if (empty($translate->$seccion))
            {
                $this->_translate[$translate->$colLocale][$messageId] = $translate->$colMessage;
            } else
            {
                $this->_translate[$translate->$colLocale][$translate->$seccion][$messageId] = $translate->$colMessage;
            }
        }
    }

    public function toString()
    {
        return 'Db';
    }

    public function translate($messageId, $locale = null)
    {
        $seccion = '';

        /**
         * Si el mensaje a traducir lo separo en dos partes
         * la primera es el mensaje en si, y la segunda pasa a ser la
         * seccion
         */
        if (is_array($messageId))
        {
            $seccion = $messageId[1];
            $messageId = $messageId[0];
        }
        if ($locale === null)
        {
            $locale = $this->_options['locale'];
        }

        /**
         * Si hay error de locale logueo el mensaje
         */
        if (!Zend_Locale::isLocale($locale, true, false))
        {
            if (!Zend_Locale::isLocale($locale, false, false))
            {
                $this->_log($messageId, $locale);
                return $messageId;
            }

            $locale = new Zend_Locale($locale);
        }
        /**
         * Locale completo
         * @example es, es_ES,en_US
         */
        $idi_pais = (string)$locale;

        /**
         * Retorno en caso de que exista la traduccion en la seccion y
         * el locale completo
         */
        if (isset($this->_translate[$idi_pais][$seccion][$messageId]))
        {
            return $this->_translate[$idi_pais][$seccion][$messageId];
        }

        /**
         * Del ejemplo anterior
         * @example es,es,en
         */
        $idi = substr($locale, 0, -strlen(strrchr($locale, '_')));

        /**
         * Retorno en caso de que exita la traduccion en la seccion y
         * el idioma generico
         */
        if (isset($this->_translate[$idi][$seccion][$messageId]))
        {
            return $this->_translate[$idi][$seccion][$messageId];
        }

        /**
         * Retorno en caso de que exista la traduccion en el locale completo
         */
        if (isset($this->_translate[$idi_pais][$messageId]))
        {
            return $this->_translate[$idi_pais][$messageId];
        }

        /**
         * Retorno en caso de que exista la traduccion en el idioma generico
         */
        if (isset($this->_translate[$idi][$messageId]))
        {
            return $this->_translate[$idi][$messageId];
        }

        /**
         * Si no lo encuentra lo loguea y retorna el mismo mensaje
         */
        $this->_log($messageId, $idi_pais, $seccion);
        return $messageId;
    }

    public function _log($messageId, $locale, $seccion='')
    {
        try
        {
            $dbTable = $this->_db;
            if (is_string($dbTable))
            {
                require_once 'Zend/Loader.php';
                Zend_Loader::loadClass($dbTable);
                $dbTable = new $dbTable;
            }

            /**
             * Registra en la misma tabla con el fin de poder ver las cadenas
             * necesarias de traduccion desde alguna clase de panel de admin
             */
            if ($dbTable instanceof Zend_Db_Table_Abstract)
            {
                $datos = array(
                    $this->_tableColumns[self::ZTAD_MENSAJE_ID] => $messageId,
                    $this->_tableColumns[self::ZTAD_LOCALE] => $locale,
                    $this->_tableColumns[self::ZTAD_MENSAJE] => $messageId,
                );

                if (!empty($this->_tableColumns[self::ZTAD_SECCION]))
                {
                    $datos[$this->_tableColumns[self::ZTAD_SECCION]] = $seccion;
                }

                $dbTable->insert($datos);
            } else
            {
                parent::_log($messageId, $locale);
            }
        } catch (Exception $e)
        {

        }
    }

    /**
     * Al tener un un indice unico se logra obtener una excepcion cuando se
     * intenta loguear dos veces la misma cadena para un idioma y seccion
     * especificos. El problema es que el limite de un indice unico son 1000
     * caracteres, de esta manera si un texto tiene mas de 944/994 caraceteres
     * y cambia solo despues de los 944/994 con la seccion o sin la seccion
     * correspondientemente, habra una excepcion.
     * 
     * @todo Lograr capturar la excepcion de MySQL cuando la tabla no existe
     * y con el adaptador por defecto lograr instalar la tabla
     */
    public function __installSQL()
    {
        throw new Exception('Todavia no implementado');

        /**
         * Esto retorna error porque no se puede tomar una variable protegida
         * de la instacia de Zend_Db_Table_Abstract
         */
        $tabla = $this->_db->_name;
        $datos = array(
            $this->_tableColumns[self::ZTAD_MENSAJE_ID] => $messageId,
            $this->_tableColumns[self::ZTAD_LOCALE] => $locale,
            $this->_tableColumns[self::ZTAD_MENSAJE] => $messageId,
        );

        if (!empty($this->_tableColumns[self::ZTAD_SECCION]))
        {
            /**
             * Si no esta seteada la columna de seccion entonces crea la tabla
             */
            $sql = <<<SQL_QUERY
CREATE TABLE IF NOT EXISTS `{$tabla}` (
  `id_ai_traduccion` int(11) NOT NULL AUTO_INCREMENT,
  `{$this->_tableColumns[self::ZTAD_MENSAJE_ID]}` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
  `{$this->_tableColumns[self::ZTAD_LOCALE]}` varchar(6) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL DEFAULT 'en',
  `{$this->_tableColumns[self::ZTAD_MENSAJE]}` text CHARACTER SET latin1 COLLATE latin1_general_cs,
  `stat` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id_ai_traduccion`),
  UNIQUE KEY `id_u_trans_unica` (`{$this->_tableColumns[self::ZTAD_MENSAJE_ID]}`(994),`{$this->_tableColumns[self::ZTAD_LOCALE]}`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
SQL_QUERY;
        } else
        {
            /**
             * De tener columna de seccion la agrega tambien al indice unico
             */
            $sql = <<<SQL_QUERY
CREATE TABLE IF NOT EXISTS `{$tabla}` (
  `id_ai_traduccion` int(11) NOT NULL AUTO_INCREMENT,
  `{$this->_tableColumns[self::ZTAD_MENSAJE_ID]}` text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
  `{$this->_tableColumns[self::ZTAD_LOCALE]}` varchar(6) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL DEFAULT 'en',
  `{$this->_tableColumns[self::ZTAD_MENSAJE]}` text CHARACTER SET latin1 COLLATE latin1_general_cs,
  `{$this->_tableColumns[self::ZTAD_SECCION]}` varchar(50) CHARACTER SET latin1 COLLATE latin1_general_cs DEFAULT '',
  `stat` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id_ai_traduccion`),
  UNIQUE KEY `id_u_trans_unica` (`{$this->_tableColumns[self::ZTAD_MENSAJE_ID]}`(944),`{$this->_tableColumns[self::ZTAD_LOCALE]}`,`{$this->_tableColumns[self::ZTAD_SECCION]}`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
SQL_QUERY;
        }

        $db = Zend_Db_Table_Abstract::getDefaultAdapter()->query($sql);
        return $this;
    }
}